home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / Filezilla Server / FileZilla_Server-0_9_41.exe / source / Permissions.cpp < prev    next >
C/C++ Source or Header  |  2012-02-20  |  63KB  |  2,236 lines

  1. // FileZilla Server - a Windows ftp server
  2.  
  3. // Copyright (C) 2002-2004 - Tim Kosse <tim.kosse@gmx.de>
  4.  
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9.  
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14.  
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. // Permissions.cpp: Implementierung der Klasse CPermissions.
  20. //
  21. //////////////////////////////////////////////////////////////////////
  22.  
  23. #include "stdafx.h"
  24. #include "misc\md5.h"
  25. #include "Permissions.h"
  26. #include "tinyxml/tinyxml.h"
  27. #include "xml_utils.h"
  28. #include "options.h"
  29. #include "iputils.h"
  30.  
  31. #ifdef _DEBUG
  32. #undef THIS_FILE
  33. static char THIS_FILE[]=__FILE__;
  34. #endif
  35.  
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CPermissionsHelperWindow
  38.  
  39. class CPermissionsHelperWindow
  40. {
  41. public:
  42.     CPermissionsHelperWindow(CPermissions *pPermissions)
  43.     {
  44.         ASSERT(pPermissions);
  45.         m_pPermissions = pPermissions;
  46.  
  47.         //Create window
  48.         WNDCLASSEX wndclass;
  49.         wndclass.cbSize = sizeof wndclass;
  50.         wndclass.style = 0;
  51.         wndclass.lpfnWndProc = WindowProc;
  52.         wndclass.cbClsExtra = 0;
  53.         wndclass.cbWndExtra = 0;
  54.         wndclass.hInstance = GetModuleHandle(0);
  55.         wndclass.hIcon = 0;
  56.         wndclass.hCursor = 0;
  57.         wndclass.hbrBackground = 0;
  58.         wndclass.lpszMenuName = 0;
  59.         wndclass.lpszClassName = _T("CPermissions Helper Window");
  60.         wndclass.hIconSm = 0;
  61.  
  62.         RegisterClassEx(&wndclass);
  63.  
  64.         m_hWnd=CreateWindow(_T("CPermissions Helper Window"), _T("CPermissions Helper Window"), 0, 0, 0, 0, 0, 0, 0, 0, GetModuleHandle(0));
  65.         ASSERT(m_hWnd);
  66.         SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG)this);
  67.     };
  68.  
  69.     virtual ~CPermissionsHelperWindow()
  70.     {
  71.         //Destroy window
  72.         if (m_hWnd)
  73.         {
  74.             DestroyWindow(m_hWnd);
  75.             m_hWnd = 0;
  76.         }
  77.     }
  78.  
  79.     HWND GetHwnd()
  80.     {
  81.         return m_hWnd;
  82.     }
  83.  
  84. protected:
  85.     static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  86.     {
  87.         if (message==WM_USER)
  88.         {
  89.             /* If receiving WM_USER, update the permission data of the instance with the permission
  90.              * data from the global data
  91.              */
  92.  
  93.             // Get own instance
  94.             CPermissionsHelperWindow *pWnd=(CPermissionsHelperWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  95.             if (!pWnd)
  96.                 return 0;
  97.             if (!pWnd->m_pPermissions)
  98.                 return 0;
  99.     
  100.             EnterCritSection(pWnd->m_pPermissions->m_sync);
  101.     
  102.             // Clear old group data and copy over the new data
  103.             pWnd->m_pPermissions->m_GroupsList.clear();
  104.             for (CPermissions::t_GroupsList::iterator groupiter=pWnd->m_pPermissions->m_sGroupsList.begin(); groupiter!=pWnd->m_pPermissions->m_sGroupsList.end(); groupiter++)
  105.                 pWnd->m_pPermissions->m_GroupsList.push_back(*groupiter);
  106.     
  107.             // Clear old user data and copy over the new data
  108.             pWnd->m_pPermissions->m_UsersList.clear();
  109.             for (CPermissions::t_UsersList::iterator iter=pWnd->m_pPermissions->m_sUsersList.begin(); iter!=pWnd->m_pPermissions->m_sUsersList.end(); iter++)
  110.             {
  111.                 CUser user = *iter;
  112.                 user.pOwner = NULL;
  113.                 if (user.group != _T(""))
  114.                 {    // Set owner
  115.                     for (CPermissions::t_GroupsList::iterator groupiter=pWnd->m_pPermissions->m_GroupsList.begin(); groupiter!=pWnd->m_pPermissions->m_GroupsList.end(); groupiter++)
  116.                         if (groupiter->group == user.group)
  117.                         {
  118.                             user.pOwner = &(*groupiter);
  119.                             break;
  120.                         }
  121.                 }
  122.                 pWnd->m_pPermissions->m_UsersList.push_back(user);
  123.             }
  124.     
  125.             LeaveCritSection(pWnd->m_pPermissions->m_sync);
  126.         }
  127.         return ::DefWindowProc(hWnd, message, wParam, lParam);
  128.     }
  129.  
  130. protected:
  131.     CPermissions *m_pPermissions;
  132.  
  133. private:
  134.     HWND m_hWnd;
  135. };
  136.  
  137. /////////////////////////////////////////////////////////////////////////////
  138. // CPermissions
  139.  
  140. CCriticalSectionWrapper CPermissions::m_sync;
  141. CPermissions::t_UsersList CPermissions::m_sUsersList;
  142. CPermissions::t_GroupsList CPermissions::m_sGroupsList;
  143. std::list<CPermissions *> CPermissions::m_sInstanceList;
  144.  
  145. //////////////////////////////////////////////////////////////////////
  146. // Konstruktion/Destruktion
  147. //////////////////////////////////////////////////////////////////////
  148.  
  149. CPermissions::CPermissions()
  150. {
  151.     Init();
  152. }
  153.  
  154. CPermissions::~CPermissions()
  155. {
  156.     EnterCritSection(m_sync);
  157.     std::list<CPermissions *>::iterator instanceIter;
  158.     for (instanceIter=m_sInstanceList.begin(); instanceIter!=m_sInstanceList.end(); instanceIter++)
  159.         if (*instanceIter==this)
  160.             break;
  161.     ASSERT(instanceIter != m_sInstanceList.end());
  162.     if (instanceIter != m_sInstanceList.end())
  163.         m_sInstanceList.erase(instanceIter);
  164.     LeaveCritSection(m_sync);
  165.     if (m_pPermissionsHelperWindow)
  166.         delete m_pPermissionsHelperWindow;
  167. }
  168.  
  169. void CPermissions::AddLongListingEntry(t_dirlisting *&pResult, bool isDir, const char* name, const t_directory& directory, __int64 size, FILETIME* pTime, const char* dirToDisplay, bool *)
  170. {
  171.     CFileStatus64 status;
  172.     if (!pTime && GetStatus64(directory.dir, status))
  173.     {
  174.         size = status.m_size;
  175.         pTime = &status.m_mtime;
  176.     }
  177.  
  178.     unsigned int nameLen = strlen(name);
  179.  
  180.     // This wastes some memory but keeps the whole thing fast
  181.     if ((8192 - pResult->len) < (60 + nameLen))
  182.     {
  183.         pResult->pNext = new t_dirlisting;
  184.         pResult = pResult->pNext;
  185.         pResult->len = 0;
  186.         pResult->pNext = NULL;
  187.     }
  188.  
  189.     if (isDir)
  190.     {
  191.         memcpy(pResult->buffer + pResult->len, "drwxr-xr-x", 10);
  192.         pResult->len += 10;
  193.     }
  194.     else
  195.     {
  196.         pResult->buffer[pResult->len++] = '-';
  197.         pResult->buffer[pResult->len++] = directory.bFileRead ? 'r' : '-';
  198.         pResult->buffer[pResult->len++] = directory.bFileWrite ? 'w' : '-';
  199.  
  200.         BOOL isexe = FALSE;
  201.         if (nameLen > 4)
  202.         {
  203.             CStdStringA ext = name + nameLen - 4;
  204.             ext.MakeLower();
  205.             if (ext.ReverseFind('.')!=-1)
  206.             {
  207.                 if (ext == ".exe")
  208.                     isexe = TRUE;
  209.                 else if (ext == ".bat")
  210.                     isexe = TRUE;
  211.                 else if (ext == ".com")
  212.                     isexe = TRUE;
  213.             }
  214.         }
  215.         pResult->buffer[pResult->len++] = isexe ? 'x' : '-';
  216.         pResult->buffer[pResult->len++] = directory.bFileRead ? 'r' : '-';
  217.         pResult->buffer[pResult->len++] = '-';
  218.         pResult->buffer[pResult->len++] = isexe ? 'x' : '-';
  219.         pResult->buffer[pResult->len++] = directory.bFileRead ? 'r' : '-';
  220.         pResult->buffer[pResult->len++] = '-';
  221.         pResult->buffer[pResult->len++] = isexe ? 'x' : '-';
  222.     }
  223.  
  224.     memcpy(pResult->buffer + pResult->len, " 1 ftp ftp ", 11);
  225.     pResult->len += 11;
  226.  
  227.     pResult->len += sprintf(pResult->buffer + pResult->len, "% 14I64d", size);
  228.  
  229.     // Adjust time zone info and output file date/time
  230.     SYSTEMTIME sLocalTime;
  231.     GetLocalTime(&sLocalTime);
  232.     FILETIME fTime;
  233.     VERIFY(SystemTimeToFileTime(&sLocalTime, &fTime));
  234.  
  235.     FILETIME mtime;
  236.     if (pTime)
  237.         mtime = *pTime;
  238.     else
  239.         mtime = fTime;
  240.  
  241.     TIME_ZONE_INFORMATION tzInfo;
  242.     int tzRes = GetTimeZoneInformation(&tzInfo);
  243.     _int64 offset = tzInfo.Bias+((tzRes==TIME_ZONE_ID_DAYLIGHT)?tzInfo.DaylightBias:tzInfo.StandardBias);
  244.     offset *= 60 * 10000000;
  245.  
  246.     _int64 t1 = ((_int64)mtime.dwHighDateTime<<32) + mtime.dwLowDateTime;
  247.     t1 -= offset;
  248.     mtime.dwHighDateTime = (DWORD)(t1>>32);
  249.     mtime.dwLowDateTime = (DWORD)(t1%0xFFFFFFFF);
  250.  
  251.     SYSTEMTIME sFileTime;
  252.     FileTimeToSystemTime(&mtime, &sFileTime);
  253.  
  254.     _int64 t2 = ((_int64)fTime.dwHighDateTime<<32) + fTime.dwLowDateTime;
  255.     const char months[][4]={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  256.     pResult->len += sprintf(pResult->buffer + pResult->len, " %s %02d ", months[sFileTime.wMonth-1], sFileTime.wDay);
  257.     if (t1 > t2 || (t2-t1) > ((_int64)1000000*60*60*24*350))
  258.         pResult->len += sprintf(pResult->buffer + pResult->len, " %d ", sFileTime.wYear);
  259.     else
  260.         pResult->len += sprintf(pResult->buffer + pResult->len, "%02d:%02d ", sFileTime.wHour, sFileTime.wMinute);
  261.  
  262.     memcpy(pResult->buffer + pResult->len, name, nameLen);
  263.     pResult->len += nameLen;
  264.     pResult->buffer[pResult->len++] = '\r';
  265.     pResult->buffer[pResult->len++] = '\n';
  266. }
  267.  
  268. void CPermissions::AddFactsListingEntry(t_dirlisting *&pResult, bool isDir, const char* name, const t_directory& directory, __int64 size, FILETIME* pTime, const char* dirToDisplay, bool *enabledFacts)
  269. {
  270.     CFileStatus64 status;
  271.     if (!pTime && GetStatus64(directory.dir, status))
  272.     {
  273.         size = status.m_size;
  274.         pTime = &status.m_mtime;
  275.     }
  276.  
  277.     unsigned int nameLen = strlen(name);
  278.  
  279.     // This wastes some memory but keeps the whole thing fast
  280.     if ((8192 - pResult->len) < (76 + nameLen))
  281.     {
  282.         pResult->pNext = new t_dirlisting;
  283.         pResult = pResult->pNext;
  284.         pResult->len = 0;
  285.         pResult->pNext = NULL;
  286.     }
  287.  
  288.     if (!enabledFacts || enabledFacts[0])
  289.     {
  290.         if (isDir)
  291.         {
  292.             memcpy(pResult->buffer + pResult->len, "type=dir;", 9);
  293.             pResult->len += 9;
  294.         }
  295.         else
  296.         {
  297.             memcpy(pResult->buffer + pResult->len, "type=file;", 10);
  298.             pResult->len += 10;
  299.         }
  300.     }
  301.  
  302.     // Adjust time zone info and output file date/time
  303.     SYSTEMTIME sLocalTime;
  304.     GetLocalTime(&sLocalTime);
  305.     FILETIME fTime;
  306.     VERIFY(SystemTimeToFileTime(&sLocalTime, &fTime));
  307.  
  308.     FILETIME mtime;
  309.     if (pTime)
  310.         mtime = *pTime;
  311.     else
  312.         mtime = fTime;
  313.  
  314.     if (!enabledFacts || enabledFacts[2])
  315.     {
  316.         if (mtime.dwHighDateTime || mtime.dwLowDateTime)
  317.         {
  318.             SYSTEMTIME time;
  319.             FileTimeToSystemTime(&mtime, &time);
  320.             CStdStringA str;
  321.             str.Format("modify=%04d%02d%02d%02d%02d%02d;",
  322.                 time.wYear,
  323.                 time.wMonth,
  324.                 time.wDay,
  325.                 time.wHour,
  326.                 time.wMinute,
  327.                 time.wSecond);
  328.  
  329.             memcpy(pResult->buffer + pResult->len, str.c_str(), str.GetLength());
  330.             pResult->len += str.GetLength();
  331.         }
  332.     }
  333.  
  334.     if (!enabledFacts || enabledFacts[1])
  335.     {
  336.         if (!isDir)
  337.             pResult->len += sprintf(pResult->buffer + pResult->len, "size=%I64d;", size);
  338.     }
  339.  
  340.     if (enabledFacts && enabledFacts[fact_perm])
  341.     {
  342.         // TODO: a, d,f,p,r,w
  343.         memcpy(pResult->buffer + pResult->len, "perm=", 5);
  344.         pResult->len += 5;
  345.         if (isDir)
  346.         {
  347.             if (directory.bFileWrite)
  348.                 pResult->buffer[pResult->len++] = 'c';
  349.             pResult->buffer[pResult->len++] = 'e';
  350.             if (directory.bDirList)
  351.                 pResult->buffer[pResult->len++] = 'l';
  352.             if (directory.bFileDelete || directory.bDirDelete)
  353.                 pResult->buffer[pResult->len++] = 'p';
  354.         }
  355.         else
  356.         {
  357.         }    
  358.     }
  359.  
  360.     pResult->len += sprintf(pResult->buffer + pResult->len, " %s\r\n", name);
  361. }
  362.  
  363. void CPermissions::AddShortListingEntry(t_dirlisting *&pResult, bool isDir, const char* name, const t_directory& directory, __int64 size, FILETIME* pTime, const char* dirToDisplay, bool *)
  364. {
  365.     unsigned int nameLen = strlen(name);
  366.     unsigned int dirToDisplayLen = strlen(dirToDisplay);
  367.  
  368.     // This wastes some memory but keeps the whole thing fast
  369.     if ((8192 - pResult->len) < (10 + nameLen + dirToDisplayLen))
  370.     {
  371.         pResult->pNext = new t_dirlisting;
  372.         pResult = pResult->pNext;
  373.         pResult->len = 0;
  374.         pResult->pNext = NULL;
  375.     }
  376.  
  377.     memcpy(pResult->buffer + pResult->len, dirToDisplay, dirToDisplayLen);
  378.     pResult->len += dirToDisplayLen;
  379.     memcpy(pResult->buffer + pResult->len, name, nameLen);
  380.     pResult->len += nameLen;
  381.     pResult->buffer[pResult->len++] = '\r';
  382.     pResult->buffer[pResult->len++] = '\n';
  383. }
  384.  
  385. int CPermissions::GetDirectoryListing(LPCTSTR username, CStdString currentDir, CStdString dirToDisplay,
  386.                                       t_dirlisting *&pResult, CStdString& physicalDir, 
  387.                                       CStdString& logicalDir, void (*addFunc)(t_dirlisting *&pResult, bool isDir, const char* name, const t_directory& directory, __int64 size, FILETIME* pTime, const char* dirToDisplay, bool *enabledFacts),
  388.                                       bool useUTF8, bool *enabledFacts /*=0*/)
  389. {
  390.     // Get user
  391.     CUser user;
  392.     if (!GetUser(username, user))
  393.         return PERMISSION_DENIED;
  394.  
  395.     CStdString dir = CanonifyServerDir(currentDir, dirToDisplay);
  396.     if (dir == _T(""))
  397.         return PERMISSION_INVALIDNAME;
  398.     logicalDir = dir;
  399.  
  400.     // Get directory from directory name
  401.     t_directory directory;
  402.     BOOL bTruematch;
  403.     int res = GetRealDirectory(dir, user, directory, bTruematch);
  404.     CStdString sFileSpec = _T("*"); // Which files to list in the directory
  405.     if (res == PERMISSION_FILENOTDIR || res == PERMISSION_NOTFOUND) // Try listing using a direct wildcard filespec instead?
  406.     {
  407.         // Check dirToDisplay if we are allowed to go back a directory
  408.         dirToDisplay.Replace('\\', '/');
  409.         while (dirToDisplay.Replace(_T("//"), _T("/")));
  410.         if (dirToDisplay.Right(1) == _T("/"))
  411.             return res;
  412.         int pos = dirToDisplay.ReverseFind('/');
  413.         if (res != PERMISSION_FILENOTDIR && dirToDisplay.Mid(pos + 1).Find('*') == -1)
  414.             return res;
  415.         dirToDisplay = dirToDisplay.Left(pos + 1);
  416.  
  417.         if (dir == _T("/"))
  418.             return res;
  419.         
  420.         pos = dir.ReverseFind('/');
  421.         sFileSpec = dir.Mid(pos + 1);
  422.         if (pos)
  423.             dir = dir.Left(pos);
  424.         else
  425.             dir = _T("/");
  426.  
  427.         if (sFileSpec.Find(_T("*")) == -1 && res != PERMISSION_FILENOTDIR)
  428.             return res;
  429.  
  430.         res = GetRealDirectory(dir, user, directory, bTruematch);
  431.     }
  432.     if (res)
  433.         return res;
  434.  
  435.     // Check permissions
  436.     if (!directory.bDirList)
  437.         return PERMISSION_DENIED;
  438.  
  439.     TIME_ZONE_INFORMATION tzInfo;
  440.     int tzRes = GetTimeZoneInformation(&tzInfo);
  441.     _int64 offset = tzInfo.Bias+((tzRes==TIME_ZONE_ID_DAYLIGHT)?tzInfo.DaylightBias:tzInfo.StandardBias);
  442.     offset *= 60 * 10000000;
  443.  
  444.     if (dirToDisplay != _T("") && dirToDisplay.Right(1) != _T("/"))
  445.         dirToDisplay += _T("/");
  446.  
  447.     t_dirlisting *pDir = new t_dirlisting;
  448.     pDir->len = 0;
  449.     pDir->pNext = NULL;
  450.     pResult = pDir;
  451.  
  452.     char* dirToDisplayUTF8 = ConvertFilename(dirToDisplay, useUTF8);
  453.     if (!dirToDisplayUTF8)
  454.         return PERMISSION_DENIED;
  455.         
  456.     // List aliases in current directory
  457.     for (std::multimap<CStdString, CUser::t_alias>::const_iterator iter = user.aliasMap.begin(); iter != user.aliasMap.end(); iter++)
  458.     {
  459.         if (iter->first.CompareNoCase(directory.dir))
  460.             continue;
  461.  
  462.         t_directory directory;
  463.         BOOL truematch = false;
  464.         if (GetRealDirectory(dir + _T("/") + iter->second.name, user, directory, truematch))
  465.             continue;
  466.         if (!directory.bDirList)
  467.             continue;
  468.         if (!truematch && !directory.bDirSubdirs)
  469.             continue;
  470.  
  471.         if (sFileSpec != _T("*.*") && sFileSpec != _T("*"))
  472.         {
  473.             if (!WildcardMatch(iter->second.name, sFileSpec))
  474.                 continue;
  475.         }
  476.  
  477.         char* name = ConvertFilename(iter->second.name, useUTF8);
  478.         if (name)
  479.         {
  480.             addFunc(pDir, true, name, directory, 0, 0, dirToDisplayUTF8, enabledFacts);
  481.             delete [] name;
  482.         }
  483.     }
  484.  
  485.     for (std::multimap<CStdString, CStdString>::const_iterator iter = user.virtualAliasNames.begin(); iter != user.virtualAliasNames.end(); iter++)
  486.     {
  487.         if (iter->first.CompareNoCase(dir))
  488.             continue;
  489.  
  490.         t_directory directory;
  491.         BOOL truematch = false;
  492.         if (GetRealDirectory(dir + _T("/") + iter->second, user, directory, truematch))
  493.             continue;
  494.         if (!directory.bDirList)
  495.             continue;
  496.         if (!truematch && !directory.bDirSubdirs)
  497.             continue;
  498.  
  499.         if (sFileSpec != _T("*.*") && sFileSpec != _T("*"))
  500.         {
  501.             if (!WildcardMatch(iter->second, sFileSpec))
  502.                 continue;
  503.         }
  504.  
  505.         char* name = ConvertFilename(iter->second, useUTF8);
  506.         if (name)
  507.         {
  508.             addFunc(pDir, true, name, directory, 0, 0, dirToDisplayUTF8, enabledFacts);
  509.             delete [] name;
  510.         }
  511.     }
  512.  
  513.     physicalDir = directory.dir;
  514.     if (sFileSpec != _T("*") && sFileSpec != _T("*.*"))
  515.         physicalDir += sFileSpec;
  516.  
  517.     WIN32_FIND_DATA FindFileData;
  518.     WIN32_FIND_DATA NextFindFileData;
  519.     HANDLE hFind;
  520.     hFind = FindFirstFile(directory.dir + _T("\\") + sFileSpec, &NextFindFileData);
  521.     while (hFind != INVALID_HANDLE_VALUE)
  522.     {
  523.         FindFileData = NextFindFileData;
  524.         if (!FindNextFile(hFind, &NextFindFileData))
  525.         {
  526.             FindClose(hFind);
  527.             hFind = INVALID_HANDLE_VALUE;
  528.         }
  529.  
  530.         if (!_tcscmp(FindFileData.cFileName, _T(".")) || !_tcscmp(FindFileData.cFileName, _T("..")))
  531.             continue;
  532.  
  533.         const CStdString& fn = FindFileData.cFileName;
  534.         
  535.         if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  536.         {
  537.             // Check permissions of subdir. If we don't have LIST permission,
  538.             // don't display the subdir.
  539.             BOOL truematch;
  540.             t_directory subDir;
  541.             if (GetRealDirectory(dir + _T("/") + fn, user, subDir, truematch))
  542.                 continue;
  543.  
  544.             if (subDir.bDirList)
  545.             {
  546.                 char* utf8 = ConvertFilename(fn, useUTF8);
  547.                 if (!utf8)
  548.                     continue;
  549.                 addFunc(pDir, true, utf8, subDir, 0, &FindFileData.ftLastWriteTime, dirToDisplayUTF8, enabledFacts);
  550.                 delete [] utf8;
  551.             }
  552.         }
  553.         else
  554.         {
  555.             char* utf8 = ConvertFilename(fn, useUTF8);
  556.             if (!utf8)
  557.                 continue;
  558.             addFunc(pDir, false, utf8, directory, FindFileData.nFileSizeLow + ((_int64)FindFileData.nFileSizeHigh<<32), &FindFileData.ftLastWriteTime, dirToDisplayUTF8, enabledFacts);
  559.             delete [] utf8;
  560.         }
  561.     }
  562.  
  563.     delete [] dirToDisplayUTF8;
  564.  
  565.     return 0;
  566. }
  567.  
  568. int CPermissions::CheckDirectoryPermissions(LPCTSTR username, CStdString dirname, CStdString currentdir, int op, CStdString& physicalDir, CStdString& logicalDir)
  569. {
  570.     //Get user from username
  571.     CUser user;
  572.     if (!GetUser(username, user))
  573.         return PERMISSION_DENIED; // No user found
  574.  
  575.     CStdString dir = CanonifyServerDir(currentdir, dirname);
  576.     if (dir == _T(""))
  577.         return PERMISSION_INVALIDNAME;
  578.     if (dir == _T("/"))
  579.         return PERMISSION_NOTFOUND;
  580.  
  581.     int pos = dir.ReverseFind('/');
  582.     if (pos == -1 || !dir[pos + 1])
  583.         return PERMISSION_NOTFOUND;
  584.     logicalDir = dir;
  585.     dirname = dir.Mid(pos + 1);
  586.     if (!pos)
  587.         dir = _T("/");
  588.     else
  589.         dir = dir.Left(pos);
  590.     
  591.     // dir now is the absolute path (logical server path of course)
  592.     // awhile dirname is the pure dirname without the full path
  593.  
  594.     CStdString realDir;
  595.     CStdString realDirname;
  596.  
  597.     //Get the physical path, only of dir to get the right permissions
  598.     t_directory directory;
  599.     BOOL truematch;
  600.     int res;
  601.  
  602.     CStdString dir2 = dir;
  603.     CStdString dirname2 = dirname;
  604.     do
  605.     {
  606.         res = GetRealDirectory(dir2, user, directory, truematch);
  607.         if (res & PERMISSION_NOTFOUND && op == DOP_CREATE)
  608.         { //that path could not be found. Maybe more than one directory level has to be created, check that
  609.             if (dir2 == _T("/"))
  610.                 return res;
  611.  
  612.             int pos = dir2.ReverseFind('/');
  613.             if (pos == -1)
  614.                 return res;
  615.  
  616.             dirname2 = dir2.Mid(pos+1) + _T("/") + dirname2;
  617.             if (pos)
  618.                 dir2 = dir2.Left(pos);
  619.             else
  620.                 dir2 = _T("/");
  621.  
  622.             continue;
  623.         }
  624.         else if (res)
  625.             return res;
  626.         
  627.         realDir = directory.dir;
  628.         realDirname = dirname2;
  629.         if (!directory.bDirDelete && op & DOP_DELETE)
  630.             res |= PERMISSION_DENIED;
  631.         if (!directory.bDirCreate && op & DOP_CREATE)
  632.             res |= PERMISSION_DENIED;
  633.         break;
  634.     } while (TRUE);
  635.  
  636.     realDirname.Replace(_T("/"), _T("\\"));
  637.     physicalDir = realDir + _T("\\") + realDirname;
  638.  
  639.     //Check if dir + dirname is a valid path
  640.     int res2 = GetRealDirectory(dir + _T("/") + dirname, user, directory, truematch);
  641.  
  642.     if (!res2)
  643.         physicalDir = directory.dir;
  644.     
  645.     if (!res2 && op&DOP_CREATE)
  646.         res |= PERMISSION_DOESALREADYEXIST;
  647.     else if (!(res2 & PERMISSION_NOTFOUND))
  648.         return res | res2;
  649.  
  650.     // check dir attributes
  651.     DWORD nAttributes = GetFileAttributes(physicalDir);
  652.     if (nAttributes==0xFFFFFFFF && !(op&DOP_CREATE))
  653.         res |= PERMISSION_NOTFOUND;
  654.     else if (!(nAttributes&FILE_ATTRIBUTE_DIRECTORY))
  655.         res |= PERMISSION_FILENOTDIR;
  656.  
  657.     //Finally, a valid path+dirname!
  658.     return res;
  659. }
  660.  
  661. int CPermissions::CheckFilePermissions(LPCTSTR username, CStdString filename, CStdString currentdir, int op, CStdString& physicalFile, CStdString& logicalFile)
  662. {
  663.     //Get user from username
  664.     CUser user;
  665.     if (!GetUser(username, user))
  666.         return PERMISSION_DENIED; // No user found
  667.  
  668.     CStdString dir = CanonifyServerDir(currentdir, filename);
  669.     if (dir == _T(""))
  670.         return PERMISSION_INVALIDNAME;
  671.     if (dir == _T("/"))
  672.         return PERMISSION_NOTFOUND;
  673.  
  674.     int pos = dir.ReverseFind('/');
  675.     if (pos == -1)
  676.         return PERMISSION_NOTFOUND;
  677.  
  678.     logicalFile = dir;
  679.     
  680.     filename = dir.Mid(pos + 1);
  681.     if (pos)
  682.         dir = dir.Left(pos);
  683.     else
  684.         dir = "/";
  685.  
  686.     // dir now is the absolute path (logical server path of course)
  687.     // while filename is the filename
  688.  
  689.     //Get the physical path
  690.     t_directory directory;
  691.     BOOL truematch;
  692.     int res = GetRealDirectory(dir, user, directory, truematch);
  693.  
  694.     if (res)
  695.         return res;
  696.     if (!directory.bFileRead && op&FOP_READ)
  697.         res |= PERMISSION_DENIED;
  698.     if (!directory.bFileDelete && op&FOP_DELETE)
  699.         res |= PERMISSION_DENIED;
  700.     if (!directory.bFileWrite && op&(FOP_CREATENEW|FOP_WRITE|FOP_APPEND))
  701.         res |= PERMISSION_DENIED;
  702.     if ((!directory.bDirList || (!directory.bDirSubdirs && !truematch)) && op&FOP_LIST)
  703.         res |= PERMISSION_DENIED;
  704.  
  705.     physicalFile = directory.dir + "\\" + filename;
  706.     DWORD nAttributes = GetFileAttributes(physicalFile);
  707.     if (nAttributes == 0xFFFFFFFF)
  708.     {
  709.         if (!(op&(FOP_WRITE|FOP_APPEND|FOP_CREATENEW)))
  710.             res |= PERMISSION_NOTFOUND;
  711.     }
  712.     else
  713.     {
  714.         if (nAttributes&FILE_ATTRIBUTE_DIRECTORY)
  715.             res |= PERMISSION_DIRNOTFILE;
  716.         if (!directory.bFileAppend && op&FOP_APPEND)
  717.             res |= PERMISSION_DENIED;
  718.         if (!directory.bFileDelete && op&FOP_WRITE)
  719.             res |= PERMISSION_DENIED;
  720.         if (op & FOP_CREATENEW)
  721.             res |= PERMISSION_DOESALREADYEXIST;
  722.     }
  723.  
  724.     //If res is 0 we finally have a valid path+filename!
  725.     return res;
  726. }
  727.  
  728. CStdString CPermissions::GetHomeDir(const CUser &user, bool physicalPath /*=false*/) const
  729. {
  730.     if (user.homedir == _T(""))
  731.         return _T("");
  732.  
  733.     if (!physicalPath)
  734.         return _T("/");
  735.     
  736.     CStdString path;
  737.     path = user.homedir;
  738.     
  739.     user.DoReplacements(path);
  740.     
  741.     return path;
  742. }
  743.  
  744. CStdString CPermissions::GetHomeDir(LPCTSTR username, bool physicalPath /*=false*/) const
  745. {
  746.     CUser user;
  747.     if (!GetUser(username, user))
  748.         return _T("");
  749.  
  750.     return GetHomeDir(user, physicalPath);
  751. }
  752.  
  753. int CPermissions::GetRealDirectory(CStdString directory, const CUser &user, t_directory &ret, BOOL &truematch)
  754. {
  755.     /*
  756.      * This function translates pathnames from absolute server paths
  757.      * into absolute local paths.
  758.      * The given server directory is already an absolute canonified path, so
  759.      * parsing it is very quick.
  760.      * To find the absolute local path, we go though each segment of the server
  761.      * path. For the local path, we start form the homedir and append segments 
  762.      * sequentially or resolve aliases if required.
  763.      */
  764.  
  765.     directory.TrimLeft(_T("/"));
  766.     
  767.     // Split server path
  768.     // --------------------
  769.  
  770.     //Split dir into pieces
  771.     std::list<CStdString> PathPieces;
  772.     int pos;
  773.  
  774.     while((pos = directory.Find('/')) != -1)
  775.     {
  776.         PathPieces.push_back(directory.Left(pos));
  777.         directory = directory.Mid(pos + 1);
  778.     }
  779.     if (directory != _T(""))
  780.         PathPieces.push_back(directory);
  781.  
  782.     // Get absolute local path
  783.     // -----------------------
  784.  
  785.     //First get the home dir
  786.     CStdString homepath = GetHomeDir(user, true);
  787.     if (homepath == _T("")) //No homedir found
  788.         return PERMISSION_DENIED;
  789.     
  790.     // Reassamble path to get local path
  791.     CStdString path = homepath; // Start with homedir as root
  792.  
  793.     CStdString virtualPath = _T("/");
  794.     // Go through all pieces
  795.     for (std::list<CStdString>::const_iterator iter = PathPieces.begin(); iter != PathPieces.end(); iter++)
  796.     {
  797.         // Check if piece exists
  798.         const CStdString& piece = *iter;
  799.         virtualPath += piece + _T("/");
  800.         DWORD nAttributes = GetFileAttributes(path + _T("\\") + piece);
  801.         if (nAttributes != 0xFFFFFFFF)
  802.         {
  803.             if (!(nAttributes & FILE_ATTRIBUTE_DIRECTORY))
  804.                 return PERMISSION_FILENOTDIR;
  805.             path += _T("\\") + piece;
  806.             continue;
  807.         }
  808.         else
  809.         {
  810.             // Physical path did not exist, check aliases
  811.             const CStdString& target = user.GetAliasTarget(path, virtualPath, piece);
  812.  
  813.             if (target != _T(""))
  814.             {
  815.                 if (target.Right(1) != _T(":"))
  816.                 {
  817.                     nAttributes = GetFileAttributes(target);
  818.                     if (nAttributes == 0xFFFFFFFF)
  819.                         return PERMISSION_NOTFOUND;
  820.                     else if (!(nAttributes & FILE_ATTRIBUTE_DIRECTORY))
  821.                         return PERMISSION_FILENOTDIR;
  822.                 }
  823.                 path = target;
  824.                 continue;
  825.             }
  826.  
  827.         }
  828.         return PERMISSION_NOTFOUND;
  829.     }
  830.     const CStdString realpath = path;
  831.  
  832.     // Check permissions
  833.     // -----------------
  834.  
  835.     /* We got a valid local path, now find the closest matching path within the
  836.      * permissions.
  837.      * We do this by sequentially comparing the path with all permissions and
  838.      * sequentially removing the last path segment until we found a match or
  839.      * all path segments have been removed
  840.      * Distinguish the case
  841.      */
  842.     truematch = TRUE;
  843.     
  844.     while (path != _T(""))
  845.     {
  846.         BOOL bFoundMatch = FALSE;
  847.         unsigned int i;
  848.     
  849.         // Check user permissions
  850.         for (i = 0; i < user.permissions.size(); i++)
  851.         {
  852.             CStdString permissionPath = user.permissions[i].dir;
  853.             user.DoReplacements(permissionPath);
  854.             if (!permissionPath.CompareNoCase(path))
  855.             {
  856.                 bFoundMatch = TRUE;
  857.                 ret = user.permissions[i];
  858.                 break;
  859.             }
  860.         }
  861.  
  862.         // Check owner (group) permissions
  863.         if (!bFoundMatch && user.pOwner)
  864.             for (i = 0; i < user.pOwner->permissions.size(); i++)
  865.             {
  866.                 CStdString permissionPath = user.pOwner->permissions[i].dir;
  867.                 user.DoReplacements(permissionPath);
  868.                 if (!permissionPath.CompareNoCase(path))
  869.                 {
  870.                     bFoundMatch = TRUE;
  871.                     ret = user.pOwner->permissions[i];
  872.                     break;
  873.                 }
  874.             }
  875.  
  876.         if (!bFoundMatch)
  877.         {
  878.             // No match found, remove last segment and try again
  879.             int pos = path.ReverseFind('\\');
  880.             if (pos != -1)
  881.                 path = path.Left(pos);
  882.             else
  883.                 return PERMISSION_DENIED;
  884.             truematch = FALSE;
  885.             continue;
  886.         }
  887.         ret.dir = realpath;
  888.  
  889.         // We can check the bDirSubdirs permission right here
  890.         if (!truematch && !ret.bDirSubdirs)
  891.             return PERMISSION_DENIED;
  892.  
  893.         return 0;
  894.     }
  895.     return PERMISSION_NOTFOUND;
  896. }
  897.  
  898. int CPermissions::ChangeCurrentDir(LPCTSTR username, CStdString ¤tdir, CStdString &dir)
  899. {
  900.     //Get user from username
  901.     CUser user;
  902.     if (!GetUser(username, user))
  903.         return PERMISSION_DENIED; // No user found
  904.  
  905.     CStdString canonifiedDir = CanonifyServerDir(currentdir, dir);
  906.     if (canonifiedDir == _T(""))
  907.         return PERMISSION_INVALIDNAME;
  908.     dir = canonifiedDir;
  909.  
  910.     //Get the physical path
  911.     t_directory directory;
  912.     BOOL truematch;
  913.     int res = GetRealDirectory(dir, user, directory, truematch);
  914.     if (res)
  915.         return res;
  916.     if (!directory.bDirList)
  917.     {
  918.         if (!directory.bFileRead && !directory.bFileWrite)
  919.             return PERMISSION_DENIED;
  920.     }
  921.  
  922.     //Finally, a valid path!
  923.     currentdir = dir; //Server paths are relative, so we can use the absolute server path
  924.  
  925.     return 0;
  926. }
  927.  
  928. BOOL CPermissions::GetUser(CStdString username, CUser &userdata) const
  929. {
  930.     // Get user from username
  931.     for (unsigned int i = 0; i < m_UsersList.size(); i++)
  932.     {
  933.         if (!username.CompareNoCase(m_UsersList[i].user))
  934.         {
  935.             userdata = m_UsersList[i];
  936.             return TRUE;
  937.         }
  938.     }
  939.     return FALSE;
  940. }
  941.  
  942. BOOL CPermissions::CheckUserLogin(LPCTSTR username, LPCTSTR pass, CUser &userdata, BOOL noPasswordCheck /*=FALSE*/)
  943. {
  944.     const char *tmp = ConvToNetwork(pass);
  945.     if (!tmp)
  946.         return FALSE;
  947.  
  948.     MD5 md5;
  949.     md5.update((unsigned char *)tmp, strlen(tmp));
  950.     md5.finalize();
  951.     char *res = md5.hex_digest();
  952.     CStdString hash = res;
  953.     delete [] res;
  954.     delete [] tmp;
  955.  
  956.     CUser user;
  957.     if (!GetUser(username, user))
  958.         return FALSE;
  959.  
  960.     if (noPasswordCheck || user.password == hash || user.password == _T(""))
  961.     {
  962.         userdata = user;
  963.         return TRUE;
  964.     }
  965.  
  966.     return FALSE;
  967. }
  968.  
  969. void CPermissions::UpdateInstances()
  970. {
  971.     EnterCritSection(m_sync);
  972.     for (std::list<CPermissions *>::iterator iter=m_sInstanceList.begin(); iter!=m_sInstanceList.end(); iter++)
  973.     {
  974.         if (*iter != this)
  975.         {
  976.             ASSERT((*iter)->m_pPermissionsHelperWindow);
  977.             ::PostMessage((*iter)->m_pPermissionsHelperWindow->GetHwnd(), WM_USER, 0, 0);
  978.         }
  979.     }
  980.     LeaveCritSection(m_sync);
  981. }
  982.  
  983. void CPermissions::SetKey(TiXmlElement *pXML, LPCTSTR name, LPCTSTR value)
  984. {
  985.     ASSERT(pXML);
  986.     TiXmlElement* pOption = new TiXmlElement("Option");
  987.     pOption->SetAttribute("Name", ConvToNetwork(name));
  988.     XML::SetText(pOption, value);
  989.     pXML->LinkEndChild(pOption);
  990. }
  991.  
  992. void CPermissions::SetKey(TiXmlElement *pXML, LPCTSTR name, int value)
  993. {
  994.     ASSERT(pXML);
  995.     CStdString str;
  996.     str.Format(_T("%d"), value);
  997.     SetKey(pXML, name, str);
  998. }
  999.  
  1000. void CPermissions::SavePermissions(TiXmlElement *pXML, const t_group &user)
  1001. {
  1002.     TiXmlElement* pPermissions = new TiXmlElement("Permissions");
  1003.     pXML->LinkEndChild(pPermissions);
  1004.  
  1005.     for (unsigned int i=0; i < user.permissions.size(); i++)
  1006.     {
  1007.         TiXmlElement* pPermission = new TiXmlElement("Permission");
  1008.         pPermissions->LinkEndChild(pPermission);
  1009.  
  1010.         pPermission->SetAttribute("Dir", ConvToNetwork(user.permissions[i].dir));
  1011.         if (!user.permissions[i].aliases.empty())
  1012.         {
  1013.             TiXmlElement* pAliases = new TiXmlElement("Aliases");
  1014.             pPermission->LinkEndChild(pAliases);
  1015.             for (std::list<CStdString>::const_iterator iter = user.permissions[i].aliases.begin(); iter != user.permissions[i].aliases.end(); iter++)
  1016.             {
  1017.                 TiXmlElement *pAlias = new TiXmlElement("Alias");
  1018.                 XML::SetText(pAlias, *iter);
  1019.                 pAliases->LinkEndChild(pAlias);
  1020.             }
  1021.         }
  1022.         SetKey(pPermission, _T("FileRead"), user.permissions[i].bFileRead ? _T("1"):_T("0"));
  1023.         SetKey(pPermission, _T("FileWrite"), user.permissions[i].bFileWrite ? _T("1"):_T("0"));
  1024.         SetKey(pPermission, _T("FileDelete"), user.permissions[i].bFileDelete ?_T("1"):_T("0"));
  1025.         SetKey(pPermission, _T("FileAppend"), user.permissions[i].bFileAppend ? _T("1"):_T("0"));
  1026.         SetKey(pPermission, _T("DirCreate"), user.permissions[i].bDirCreate ? _T("1"):_T("0"));
  1027.         SetKey(pPermission, _T("DirDelete"), user.permissions[i].bDirDelete ? _T("1"):_T("0"));
  1028.         SetKey(pPermission, _T("DirList"), user.permissions[i].bDirList ? _T("1"):_T("0"));
  1029.         SetKey(pPermission, _T("DirSubdirs"), user.permissions[i].bDirSubdirs ? _T("1"):_T("0"));
  1030.         SetKey(pPermission, _T("IsHome"), user.permissions[i].bIsHome ? _T("1"):_T("0"));
  1031.         SetKey(pPermission, _T("AutoCreate"), user.permissions[i].bAutoCreate ? _T("1"):_T("0"));
  1032.     }
  1033. }
  1034.  
  1035. BOOL CPermissions::GetAsCommand(char **pBuffer, DWORD *nBufferLength)
  1036. {
  1037.     // This function returns all account data as a command string which will be 
  1038.     // sent to the user interface.
  1039.     if (!pBuffer || !nBufferLength)
  1040.         return FALSE;
  1041.  
  1042.     EnterCritSection(m_sync);
  1043.  
  1044.     // First calculate the required buffer length
  1045.     DWORD len = 4;
  1046.     t_GroupsList::iterator groupiter;
  1047.     for (groupiter = m_sGroupsList.begin(); groupiter != m_sGroupsList.end(); groupiter++)
  1048.         len += groupiter->GetRequiredBufferLen();
  1049.  
  1050.     t_UsersList::iterator iter;
  1051.     for (iter = m_sUsersList.begin(); iter != m_sUsersList.end(); iter++)
  1052.         len += iter->GetRequiredBufferLen();
  1053.  
  1054.     // Allocate memory
  1055.     *pBuffer = new char[len];
  1056.     char* p  = *pBuffer;
  1057.  
  1058.     // Write groups to buffer
  1059.     *p++ = m_sGroupsList.size()/256;
  1060.     *p++ = m_sGroupsList.size()%256;
  1061.     for (groupiter = m_sGroupsList.begin(); groupiter != m_sGroupsList.end(); groupiter++)
  1062.     {
  1063.         p = groupiter->FillBuffer(p);
  1064.         if (!p)
  1065.         {
  1066.             delete [] *pBuffer;
  1067.             *pBuffer = NULL;
  1068.             LeaveCritSection(m_sync);
  1069.             return FALSE;
  1070.         }
  1071.     }
  1072.  
  1073.     // Write users to buffer
  1074.     *p++ = m_sUsersList.size()/256;
  1075.     *p++ = m_sUsersList.size()%256;
  1076.     for (iter = m_sUsersList.begin(); iter != m_sUsersList.end(); iter++)
  1077.     {
  1078.         p = iter->FillBuffer(p);
  1079.         if (!p)
  1080.         {
  1081.             delete [] *pBuffer;
  1082.             *pBuffer = NULL;
  1083.             LeaveCritSection(m_sync);
  1084.             return FALSE;
  1085.         }
  1086.     }
  1087.  
  1088.     LeaveCritSection(m_sync);
  1089.     *nBufferLength = len;
  1090.  
  1091.     return TRUE;
  1092. }
  1093.  
  1094. BOOL CPermissions::ParseUsersCommand(unsigned char *pData, DWORD dwDataLength)
  1095. {
  1096.     m_GroupsList.clear();
  1097.     m_UsersList.clear();
  1098.     unsigned char *p = pData;
  1099.     unsigned char* endMarker = pData + dwDataLength;
  1100.  
  1101.     if (dwDataLength < 2)
  1102.         return FALSE;
  1103.     int num = *p * 256 + p[1];
  1104.     p+=2;
  1105.  
  1106.     int i;
  1107.     for (i = 0; i < num; i++)
  1108.     {
  1109.         t_group group;
  1110.         p = group.ParseBuffer(p, endMarker - p);
  1111.         if (!p)
  1112.             return FALSE;
  1113.     
  1114.         if (group.group != _T(""))
  1115.         {
  1116.             //Set a home dir if no home dir could be read
  1117.             BOOL bGotHome = FALSE;
  1118.             for (unsigned int dir = 0; dir < group.permissions.size(); dir++)
  1119.                 if (group.permissions[dir].bIsHome)
  1120.                 {
  1121.                     bGotHome = TRUE;
  1122.                     break;
  1123.                 }
  1124.  
  1125.             if (!bGotHome && !group.permissions.empty())
  1126.                 group.permissions.begin()->bIsHome = TRUE;
  1127.  
  1128.             m_GroupsList.push_back(group);
  1129.         }
  1130.     }
  1131.  
  1132.     if ((endMarker - p) < 2)
  1133.         return FALSE;
  1134.  
  1135.     num = *p * 256 + p[1];
  1136.     p+=2;
  1137.     for (i = 0; i < num; i++)
  1138.     {
  1139.         CUser user;
  1140.     
  1141.         p = user.ParseBuffer(p, endMarker - p);
  1142.         if (!p)
  1143.             return FALSE;
  1144.     
  1145.         if (user.user != _T(""))
  1146.         {
  1147.             user.pOwner = NULL;
  1148.             if (user.group != _T(""))
  1149.             {
  1150.                 for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  1151.                     if (groupiter->group == user.group)
  1152.                     {
  1153.                         user.pOwner = &(*groupiter);
  1154.                         break;
  1155.                     }
  1156.                 if (!user.pOwner)
  1157.                     user.group = _T("");
  1158.             }
  1159.  
  1160.             if (!user.pOwner)
  1161.             {
  1162.                 //Set a home dir if no home dir could be read
  1163.                 BOOL bGotHome = FALSE;
  1164.                 for (unsigned int dir = 0; dir < user.permissions.size(); dir++)
  1165.                     if (user.permissions[dir].bIsHome)
  1166.                     {
  1167.                         bGotHome = TRUE;
  1168.                         break;
  1169.                     }
  1170.  
  1171.                 if (!bGotHome && !user.permissions.empty())
  1172.                     user.permissions.begin()->bIsHome = TRUE;
  1173.             }
  1174.  
  1175.             std::vector<t_directory>::iterator iter;
  1176.             for (iter = user.permissions.begin(); iter != user.permissions.end(); iter++)
  1177.             {
  1178.                 if (iter->bIsHome)
  1179.                 {
  1180.                     user.homedir = iter->dir;
  1181.                     break;
  1182.                 }
  1183.             }
  1184.             if (user.homedir == _T("") && user.pOwner)
  1185.             {
  1186.                 for (iter = user.pOwner->permissions.begin(); iter != user.pOwner->permissions.end(); iter++)
  1187.                 {
  1188.                     if (iter->bIsHome)
  1189.                     {
  1190.                         user.homedir = iter->dir;
  1191.                         break;
  1192.                     }
  1193.                 }
  1194.             }
  1195.  
  1196.             user.PrepareAliasMap();
  1197.             m_UsersList.push_back(user);
  1198.         }
  1199.     }
  1200.  
  1201.     // Update the account list
  1202.     EnterCritSection(m_sync);
  1203.  
  1204.     m_sGroupsList.clear();
  1205.     for (t_GroupsList::const_iterator groupiter=m_GroupsList.begin(); groupiter!=m_GroupsList.end(); groupiter++)
  1206.         m_sGroupsList.push_back(*groupiter);
  1207.  
  1208.     m_sUsersList.clear();
  1209.     for (t_UsersList::const_iterator iter=m_UsersList.begin(); iter!=m_UsersList.end(); iter++)
  1210.         m_sUsersList.push_back(*iter);
  1211.  
  1212.     UpdateInstances();
  1213.  
  1214.     LeaveCritSection(m_sync);
  1215.  
  1216.     // Write the new account data into xml file
  1217.  
  1218.     TiXmlElement *pXML = COptions::GetXML();
  1219.     if (!pXML)
  1220.         return FALSE;
  1221.  
  1222.     TiXmlElement* pGroups;
  1223.     while ((pGroups = pXML->FirstChildElement("Groups")))
  1224.         pXML->RemoveChild(pGroups);
  1225.     pGroups = new TiXmlElement("Groups");
  1226.     pXML->LinkEndChild(pGroups);
  1227.  
  1228.     //Save the changed user details
  1229.     for (t_GroupsList::const_iterator groupiter=m_GroupsList.begin(); groupiter!=m_GroupsList.end(); groupiter++)
  1230.     {
  1231.         TiXmlElement* pGroup = new TiXmlElement("Group");
  1232.         pGroups->LinkEndChild(pGroup);
  1233.         
  1234.         pGroup->SetAttribute("Name", ConvToNetwork(groupiter->group));
  1235.  
  1236.         SetKey(pGroup, _T("Bypass server userlimit"), groupiter->nBypassUserLimit);
  1237.         SetKey(pGroup, _T("User Limit"), groupiter->nUserLimit);
  1238.         SetKey(pGroup, _T("IP Limit"), groupiter->nIpLimit);
  1239.         SetKey(pGroup, _T("Enabled"), groupiter->nEnabled);
  1240.         SetKey(pGroup, _T("Comments"), groupiter->comment);
  1241.         SetKey(pGroup, _T("ForceSsl"), groupiter->forceSsl);
  1242.  
  1243.         SaveIpFilter(pGroup, *groupiter);        
  1244.         SavePermissions(pGroup, *groupiter);
  1245.         SaveSpeedLimits(pGroup, *groupiter);
  1246.     }
  1247.  
  1248.     TiXmlElement* pUsers;
  1249.     while ((pUsers = pXML->FirstChildElement("Users")))
  1250.         pXML->RemoveChild(pUsers);
  1251.     pUsers = new TiXmlElement("Users");
  1252.     pXML->LinkEndChild(pUsers);
  1253.  
  1254.     //Save the changed user details
  1255.     for (t_UsersList::const_iterator iter=m_UsersList.begin(); iter!=m_UsersList.end(); iter++)
  1256.     {
  1257.         TiXmlElement* pUser = new TiXmlElement("User");
  1258.         pUsers->LinkEndChild(pUser);
  1259.         
  1260.         pUser->SetAttribute("Name", ConvToNetwork(iter->user));
  1261.  
  1262.         SetKey(pUser, _T("Pass"), iter->password);
  1263.         SetKey(pUser, _T("Group"), iter->group);
  1264.         SetKey(pUser, _T("Bypass server userlimit"), iter->nBypassUserLimit);
  1265.         SetKey(pUser, _T("User Limit"), iter->nUserLimit);
  1266.         SetKey(pUser, _T("IP Limit"), iter->nIpLimit);
  1267.         SetKey(pUser, _T("Enabled"), iter->nEnabled);
  1268.         SetKey(pUser, _T("Comments"), iter->comment);
  1269.         SetKey(pUser, _T("ForceSsl"), iter->forceSsl);
  1270.  
  1271.         SaveIpFilter(pUser, *iter);
  1272.         SavePermissions(pUser, *iter);
  1273.         SaveSpeedLimits(pUser, *iter);
  1274.     }
  1275.     if (!COptions::FreeXML(pXML, true))
  1276.         return FALSE;
  1277.  
  1278.     return TRUE;
  1279. }
  1280.  
  1281. bool CPermissions::Init()
  1282. {
  1283.     EnterCritSection(m_sync);
  1284.     m_pPermissionsHelperWindow = new CPermissionsHelperWindow(this);
  1285.     if (m_sInstanceList.empty() && m_sUsersList.empty() && m_sGroupsList.empty())
  1286.     {
  1287.         // It's the first time Init gets called after application start, read
  1288.         // permissions from xml file.
  1289.  
  1290.         ReadSettings();
  1291.     }
  1292.     else
  1293.     {
  1294.         m_GroupsList.clear();
  1295.         for (t_GroupsList::iterator groupiter = m_sGroupsList.begin(); groupiter != m_sGroupsList.end(); groupiter++)
  1296.             m_GroupsList.push_back(*groupiter);
  1297.  
  1298.         m_UsersList.clear();
  1299.         for (t_UsersList::iterator iter = m_sUsersList.begin(); iter != m_sUsersList.end(); iter++)
  1300.         {
  1301.             CUser user = *iter;
  1302.             user.pOwner = NULL;
  1303.             if (user.group != _T(""))
  1304.             {
  1305.                 for (t_GroupsList::iterator groupiter=m_GroupsList.begin(); groupiter!=m_GroupsList.end(); groupiter++)
  1306.                     if (groupiter->group == user.group)
  1307.                     {
  1308.                         user.pOwner = &(*groupiter);
  1309.                         break;
  1310.                     }
  1311.             }
  1312.             m_UsersList.push_back(user);
  1313.         }
  1314.     }
  1315.  
  1316.     std::list<CPermissions *>::iterator instanceIter;
  1317.     for (instanceIter = m_sInstanceList.begin(); instanceIter != m_sInstanceList.end(); instanceIter++)
  1318.         if (*instanceIter == this)
  1319.             break;
  1320.     if (instanceIter == m_sInstanceList.end())
  1321.         m_sInstanceList.push_back(this);
  1322.     LeaveCritSection(m_sync);
  1323.  
  1324.     return TRUE;
  1325. }
  1326.  
  1327. void CPermissions::ReadPermissions(TiXmlElement *pXML, t_group &user, BOOL &bGotHome)
  1328. {
  1329.     bGotHome = FALSE;
  1330.     for (TiXmlElement* pPermissions = pXML->FirstChildElement("Permissions"); pPermissions; pPermissions = pPermissions->NextSiblingElement("Permissions"))
  1331.     {
  1332.         for (TiXmlElement* pPermission = pPermissions->FirstChildElement("Permission"); pPermission; pPermission = pPermission->NextSiblingElement("Permission"))
  1333.         {
  1334.             t_directory dir;
  1335.             dir.dir = ConvFromNetwork(pPermission->Attribute("Dir"));
  1336.             dir.dir.Replace('/', '\\');
  1337.             dir.dir.TrimRight('\\');
  1338.             if (dir.dir == _T(""))
  1339.                 continue;
  1340.  
  1341.             for (TiXmlElement* pAliases = pPermission->FirstChildElement("Aliases"); pAliases; pAliases = pAliases->NextSiblingElement("Aliases"))
  1342.             {
  1343.                 for (TiXmlElement* pAlias = pAliases->FirstChildElement("Alias"); pAlias; pAlias = pAlias->NextSiblingElement("Alias"))
  1344.                 {
  1345.                     CStdString alias = XML::ReadText(pAlias);
  1346.                     if (alias == _T(""))
  1347.                         continue;
  1348.  
  1349.                     if (alias[0] != '/')
  1350.                     {
  1351.                         alias.Replace(_T("/"), _T("\\"));
  1352.                         bool uncPath = false;
  1353.                         if (alias.Left(2) == _T("\\\\"))
  1354.                             uncPath = true;
  1355.                         while (alias.Replace(_T("\\\\"), _T("\\")));
  1356.                         if (uncPath)
  1357.                             alias = _T("\\") + alias;
  1358.  
  1359.                         alias.TrimRight('\\');
  1360.                         if (alias != _T(""))
  1361.                             dir.aliases.push_back(alias);
  1362.                     }
  1363.                     else
  1364.                     {
  1365.                         alias.Replace(_T("\\"), _T("/"));
  1366.                         while (alias.Replace(_T("//"), _T("/")));
  1367.                         alias.TrimRight('/');
  1368.                         if (alias != _T("") && alias != _T("/"))
  1369.                             dir.aliases.push_back(alias);
  1370.                     }
  1371.                 }
  1372.             }
  1373.             for (TiXmlElement* pOption = pPermission->FirstChildElement("Option"); pOption; pOption = pOption->NextSiblingElement("Option"))
  1374.             {
  1375.                 CStdString name = ConvFromNetwork(pOption->Attribute("Name"));
  1376.                 CStdString value = XML::ReadText(pOption);
  1377.  
  1378.                 if (name == _T("FileRead"))
  1379.                     dir.bFileRead = value == _T("1");
  1380.                 else if (name == _T("FileWrite"))
  1381.                     dir.bFileWrite = value == _T("1");
  1382.                 else if (name == _T("FileDelete"))
  1383.                     dir.bFileDelete = value == _T("1");
  1384.                 else if (name == _T("FileAppend"))
  1385.                     dir.bFileAppend = value == _T("1");
  1386.                 else if (name == _T("DirCreate"))
  1387.                     dir.bDirCreate = value == _T("1");
  1388.                 else if (name == _T("DirDelete"))
  1389.                     dir.bDirDelete = value == _T("1");
  1390.                 else if (name == _T("DirList"))
  1391.                     dir.bDirList = value == _T("1");
  1392.                 else if (name == _T("DirSubdirs"))
  1393.                     dir.bDirSubdirs = value == _T("1");
  1394.                 else if (name == _T("IsHome"))
  1395.                     dir.bIsHome = value == _T("1");
  1396.                 else if (name == _T("AutoCreate"))
  1397.                     dir.bAutoCreate = value == _T("1");
  1398.             }
  1399.  
  1400.             //Avoid multiple home dirs
  1401.             if (dir.bIsHome)
  1402.                 if (!bGotHome)
  1403.                     bGotHome = TRUE;
  1404.                 else
  1405.                     dir.bIsHome = FALSE;
  1406.  
  1407.             if (user.permissions.size() < 20000)
  1408.                 user.permissions.push_back(dir);
  1409.         }
  1410.     }
  1411. }
  1412.  
  1413. void CPermissions::AutoCreateDirs(LPCTSTR username)
  1414. {
  1415.     // Create missing directores after a user has logged on
  1416.     CUser user;
  1417.     if (!GetUser(username, user))
  1418.         return;
  1419.     for (std::vector<t_directory>::iterator permissioniter = user.permissions.begin(); permissioniter != user.permissions.end(); permissioniter++)
  1420.         if (permissioniter->bAutoCreate)
  1421.         {
  1422.             CStdString dir = permissioniter->dir;
  1423.             user.DoReplacements(dir);
  1424.             
  1425.             dir += _T("\\");
  1426.             CStdString str;
  1427.             while (dir != _T(""))
  1428.             {
  1429.                 int pos = dir.Find(_T("\\"));
  1430.                 CStdString piece = dir.Left(pos + 1);
  1431.                 dir = dir.Mid(pos + 1);
  1432.                 
  1433.                 str += piece;
  1434.                 CreateDirectory(str, 0);
  1435.             }
  1436.         }
  1437.     if (user.pOwner)
  1438.         for (std::vector<t_directory>::iterator permissioniter = user.pOwner->permissions.begin(); permissioniter != user.pOwner->permissions.end(); permissioniter++)
  1439.             if (permissioniter->bAutoCreate)
  1440.             {
  1441.                 CStdString dir = permissioniter->dir;
  1442.                 user.DoReplacements(dir);
  1443.  
  1444.                 dir += _T("\\");
  1445.                 CStdString str;
  1446.                 while (dir != _T(""))
  1447.                 {
  1448.                     int pos = dir.Find(_T("\\"));
  1449.                     CStdString piece = dir.Left(pos + 1);
  1450.                     dir = dir.Mid(pos + 1);
  1451.                 
  1452.                     str += piece;
  1453.                     CreateDirectory(str, 0);
  1454.                 }
  1455.             }
  1456. }
  1457.  
  1458. void CPermissions::ReadSpeedLimits(TiXmlElement *pXML, t_group &group)
  1459. {
  1460.     const CStdString prefixes[] = { _T("Dl"), _T("Ul") };
  1461.     const char* names[] = { "Download", "Upload" };
  1462.  
  1463.     for (TiXmlElement* pSpeedLimits = pXML->FirstChildElement("SpeedLimits"); pSpeedLimits; pSpeedLimits = pSpeedLimits->NextSiblingElement("SpeedLimits"))
  1464.     {
  1465.         CStdString str;
  1466.         int n;
  1467.  
  1468.         for (int i = 0; i < 2; i++)
  1469.         {
  1470.             str = pSpeedLimits->Attribute(ConvToNetwork(prefixes[i] + _T("Type")));
  1471.             n = _ttoi(str);
  1472.             if (n >= 0 && n < 4)
  1473.                 group.nSpeedLimitType[i] = n;
  1474.             str = pSpeedLimits->Attribute(ConvToNetwork(prefixes[i] + _T("Limit")));
  1475.             n = _ttoi(str);
  1476.             if (n < 0)
  1477.                 group.nSpeedLimit[i] = 0;
  1478.             else if (n > 1048576)
  1479.                 group.nSpeedLimit[i] = 1048576;
  1480.             else
  1481.                 group.nSpeedLimit[i] = n;
  1482.  
  1483.             str = pSpeedLimits->Attribute(ConvToNetwork(_T("Server") + prefixes[i] + _T("LimitBypass")));
  1484.             n = _ttoi(str);
  1485.             if (n >= 0 && n < 4)
  1486.                 group.nBypassServerSpeedLimit[i] = n;
  1487.  
  1488.             for (TiXmlElement* pLimit = pSpeedLimits->FirstChildElement(names[i]); pLimit; pLimit = pLimit->NextSiblingElement(names[i]))
  1489.             {
  1490.                 for (TiXmlElement* pRule = pLimit->FirstChildElement("Rule"); pRule; pRule = pRule->NextSiblingElement("Rule"))
  1491.                 {
  1492.                     CSpeedLimit limit;
  1493.                     if (!limit.Load(pRule))
  1494.                         continue;
  1495.  
  1496.                     if (group.SpeedLimits[i].size() < 20000)
  1497.                         group.SpeedLimits[i].push_back(limit);
  1498.                 }
  1499.             }
  1500.         }
  1501.     }
  1502. }
  1503.  
  1504. void CPermissions::SaveSpeedLimits(TiXmlElement *pXML, const t_group &group)
  1505. {
  1506.     TiXmlElement* pSpeedLimits = pXML->LinkEndChild(new TiXmlElement("SpeedLimits"))->ToElement();
  1507.  
  1508.     CStdString str;
  1509.  
  1510.     const CStdString prefixes[] = { _T("Dl"), _T("Ul") };
  1511.     const char* names[] = { "Download", "Upload" };
  1512.  
  1513.     for (int i = 0; i < 2; i++)
  1514.     {
  1515.         pSpeedLimits->SetAttribute(ConvToNetwork(prefixes[i] + _T("Type")), group.nSpeedLimitType[i]);
  1516.         pSpeedLimits->SetAttribute(ConvToNetwork(prefixes[i] + _T("Limit")), group.nSpeedLimit[i]);
  1517.         pSpeedLimits->SetAttribute(ConvToNetwork(_T("Server") + prefixes[i] + _T("LimitBypass")), group.nBypassServerSpeedLimit[i]);
  1518.     
  1519.         TiXmlElement* pSpeedLimit = new TiXmlElement(names[i]);
  1520.         pSpeedLimits->LinkEndChild(pSpeedLimit);
  1521.  
  1522.         for (unsigned int j = 0; j < group.SpeedLimits[i].size(); j++)
  1523.         {
  1524.             CSpeedLimit limit = group.SpeedLimits[i][j];
  1525.  
  1526.             TiXmlElement* pRule = pSpeedLimit->LinkEndChild(new TiXmlElement("Rule"))->ToElement();
  1527.  
  1528.             limit.Save(pRule);
  1529.         }
  1530.     }
  1531. }
  1532.  
  1533. void CPermissions::ReloadConfig()
  1534. {
  1535.     m_UsersList.clear();
  1536.     m_GroupsList.clear();
  1537.  
  1538.     EnterCritSection(m_sync);
  1539.  
  1540.     ReadSettings();
  1541.  
  1542.     UpdateInstances();
  1543.  
  1544.     LeaveCritSection(m_sync);
  1545.  
  1546.     return;
  1547. }
  1548.  
  1549. void CPermissions::ReadIpFilter(TiXmlElement *pXML, t_group &group)
  1550. {
  1551.     for (TiXmlElement* pFilter = pXML->FirstChildElement("IpFilter"); pFilter; pFilter = pFilter->NextSiblingElement("IpFilter"))
  1552.     {
  1553.         for (TiXmlElement* pDisallowed = pFilter->FirstChildElement("Disallowed"); pDisallowed; pDisallowed = pDisallowed->NextSiblingElement("Disallowed"))
  1554.         {
  1555.             for (TiXmlElement* pIP = pDisallowed->FirstChildElement("IP"); pIP; pIP = pIP->NextSiblingElement("IP"))
  1556.             {
  1557.                 CStdString ip = XML::ReadText(pIP);
  1558.                 if (ip == _T(""))
  1559.                     continue;
  1560.  
  1561.                 if (group.disallowedIPs.size() >= 30000)
  1562.                     break;
  1563.  
  1564.                 if (ip == _T("*"))
  1565.                     group.disallowedIPs.push_back(ip);
  1566.                 else
  1567.                 {
  1568.                     if (IsValidAddressFilter(ip))
  1569.                         group.disallowedIPs.push_back(ip);
  1570.                 }
  1571.             }
  1572.         }
  1573.         for (TiXmlElement* pAllowed = pFilter->FirstChildElement("Allowed"); pAllowed; pAllowed = pAllowed->NextSiblingElement("Allowed"))
  1574.         {
  1575.             for (TiXmlElement* pIP = pAllowed->FirstChildElement("IP"); pIP; pIP = pIP->NextSiblingElement("IP"))
  1576.             {
  1577.                 CStdString ip = XML::ReadText(pIP);
  1578.                 if (ip == _T(""))
  1579.                     continue;
  1580.  
  1581.                 if (group.allowedIPs.size() >= 30000)
  1582.                     break;
  1583.  
  1584.                 if (ip == _T("*"))
  1585.                     group.allowedIPs.push_back(ip);
  1586.                 else
  1587.                 {
  1588.                     if (IsValidAddressFilter(ip))
  1589.                         group.allowedIPs.push_back(ip);
  1590.                 }
  1591.             }
  1592.         }
  1593.     }
  1594. }
  1595.  
  1596. void CPermissions::SaveIpFilter(TiXmlElement *pXML, const t_group &group)
  1597. {
  1598.     TiXmlElement* pFilter = pXML->LinkEndChild(new TiXmlElement("IpFilter"))->ToElement();
  1599.     
  1600.     TiXmlElement* pDisallowed = pFilter->LinkEndChild(new TiXmlElement("Disallowed"))->ToElement();
  1601.         
  1602.     std::list<CStdString>::const_iterator iter;
  1603.     for (iter = group.disallowedIPs.begin(); iter != group.disallowedIPs.end(); iter++)
  1604.     {
  1605.         TiXmlElement* pIP = pDisallowed->LinkEndChild(new TiXmlElement("IP"))->ToElement();
  1606.         XML::SetText(pIP, *iter);
  1607.     }
  1608.  
  1609.     TiXmlElement* pAllowed = pFilter->LinkEndChild(new TiXmlElement("Allowed"))->ToElement();
  1610.         
  1611.     for (iter = group.allowedIPs.begin(); iter != group.allowedIPs.end(); iter++)
  1612.     {
  1613.         TiXmlElement* pIP = pAllowed->LinkEndChild(new TiXmlElement("IP"))->ToElement();
  1614.         XML::SetText(pIP, *iter);
  1615.     }
  1616. }
  1617.  
  1618. CStdString CPermissions::CanonifyServerDir(CStdString currentDir, CStdString newDir) const
  1619. {
  1620.     /*
  1621.      * CanonifyPath takes the current and the new server dir as parameter,
  1622.      * concats the paths if neccessary and canonifies the dir:
  1623.      * - remove dot-segments
  1624.      * - convert backslashes into slashes
  1625.      * - remove double slashes
  1626.      */
  1627.  
  1628.     if (newDir == _T(""))
  1629.         return currentDir;
  1630.  
  1631.     // Make segment separators pretty
  1632.     newDir.Replace(_T("\\"), _T("/"));
  1633.     while (newDir.Replace(_T("//"), _T("/")));
  1634.     
  1635.     if (newDir == _T("/"))
  1636.         return newDir;
  1637.     
  1638.     // This list will hold the individual path segments
  1639.     std::list<CStdString> piecelist;
  1640.     
  1641.     /*
  1642.      * Check the type of the path: Absolute or relative?
  1643.      * On relative paths, use currentDir as base, else use
  1644.      * only dir.
  1645.      */
  1646.     if (newDir.Left(1) != _T("/"))
  1647.     {
  1648.         // New relative path, split currentDir and add it to the piece list.
  1649.         currentDir.TrimLeft(_T("/"));
  1650.         int pos;
  1651.         while((pos = currentDir.Find(_T("/"))) != -1)
  1652.         {
  1653.             piecelist.push_back(currentDir.Left(pos));
  1654.             currentDir = currentDir.Mid(pos + 1);
  1655.         }
  1656.         if (currentDir != _T(""))
  1657.             piecelist.push_back(currentDir);
  1658.     }
  1659.     
  1660.     /*
  1661.      * Now split up the new dir into individual segments. Here we
  1662.      * check for dot segments and remove the proper number of segments
  1663.      * from the piece list on dots.
  1664.      */
  1665.     
  1666.     int pos;
  1667.     newDir.TrimLeft(_T("/"));
  1668.     if (newDir.Right(1) != _T("/"))
  1669.         newDir += _T("/");
  1670.     while ((pos = newDir.Find(_T("/"))) != -1)
  1671.     {
  1672.         CStdString piece = newDir.Left(pos);
  1673.         newDir = newDir.Mid(pos + 1);
  1674.  
  1675.         if (piece == _T(""))
  1676.             continue;
  1677.  
  1678.         bool allDots = true;
  1679.         int dotCount = 0;
  1680.         for (int i = 0; i < piece.GetLength(); i++)
  1681.             if (piece[i] != '.')
  1682.             {
  1683.                 allDots = false;
  1684.                 break;
  1685.             }
  1686.             else
  1687.                 dotCount++;
  1688.  
  1689.         if (allDots)
  1690.         {
  1691.             while (--dotCount)
  1692.             {
  1693.                 if (!piecelist.empty())
  1694.                     piecelist.pop_back();
  1695.             }
  1696.         }
  1697.         else
  1698.             piecelist.push_back(piece);
  1699.     }
  1700.  
  1701.     // Reassemble the directory
  1702.     CStdString result;
  1703.  
  1704.     if (piecelist.empty())
  1705.         return _T("/");
  1706.  
  1707.     // List of reserved filenames which may not be used on a Windows system
  1708.     static LPCTSTR reservedNames[] = {    _T("CON"),    _T("PRN"),    _T("AUX"),    _T("CLOCK$"), _T("NUL"),
  1709.                                         _T("COM1"), _T("COM2"), _T("COM3"), _T("COM4"), _T("COM5"),
  1710.                                         _T("COM6"), _T("COM7"), _T("COM8"), _T("COM9"),
  1711.                                         _T("LPT1"), _T("LPT2"), _T("LPT3"), _T("LPT4"), _T("LPT5"),
  1712.                                         _T("LPT6"), _T("LPT7"), _T("LPT8"), _T("LPT9"),
  1713.                                         _T("") };
  1714.  
  1715.     for (std::list<CStdString>::iterator iter = piecelist.begin(); iter != piecelist.end(); iter++)
  1716.     {
  1717.         // Check for reserved filenames
  1718.         CStdString piece = *iter;
  1719.         piece.MakeUpper();
  1720.         for (LPCTSTR *reserved = reservedNames; **reserved; reserved++)
  1721.         {
  1722.             if (piece == *reserved)
  1723.                 return _T("");
  1724.         }
  1725.         int pos = piece.Find(_T("."));
  1726.         if (pos >= 3)
  1727.         {
  1728.             piece = piece.Left(pos);
  1729.             for (LPCTSTR *reserved = reservedNames; **reserved; reserved++)
  1730.             {
  1731.                 if (piece == *reserved)
  1732.                     return _T("");
  1733.             }
  1734.         }
  1735.  
  1736.         result += _T("/") + *iter;
  1737.     }
  1738.  
  1739.     // Now dir is the canonified absolute server path.
  1740.     return result;
  1741. }
  1742.  
  1743. int CPermissions::GetFact(LPCTSTR username, CStdString currentDir, CStdString file, CStdString& fact, CStdString& logicalName, bool enabledFacts[3])
  1744. {
  1745.     // Get user from username
  1746.     CUser user;
  1747.     if (!GetUser(username, user))
  1748.         return PERMISSION_DENIED; // No user found
  1749.  
  1750.     CStdString dir = CanonifyServerDir(currentDir, file);
  1751.     if (dir == _T(""))
  1752.         return PERMISSION_INVALIDNAME;
  1753.     logicalName = dir;
  1754.  
  1755.     t_directory directory;
  1756.     BOOL bTruematch;
  1757.     int res = GetRealDirectory(dir, user, directory, bTruematch);
  1758.     if (res == PERMISSION_FILENOTDIR)
  1759.     {
  1760.         if (dir == _T("/"))
  1761.             return res;
  1762.  
  1763.         int pos = dir.ReverseFind('/');
  1764.         if (pos == -1)
  1765.             return res;
  1766.  
  1767.         CStdString dir2;
  1768.         if (pos)
  1769.             dir2 = dir.Left(pos);
  1770.         else
  1771.             dir2 = _T("/");
  1772.  
  1773.         CStdString fn = dir.Mid(pos + 1);
  1774.         int res = GetRealDirectory(dir2, user, directory, bTruematch);
  1775.         if (res)
  1776.             return res | PERMISSION_FILENOTDIR;
  1777.  
  1778.         if (!directory.bFileRead)
  1779.             return PERMISSION_DENIED;
  1780.  
  1781.         file = directory.dir + _T("\\") + fn;
  1782.         
  1783.         if (enabledFacts[0])
  1784.             fact = _T("type=file;");
  1785.         else
  1786.             fact = _T("");
  1787.     }
  1788.     else if (res)
  1789.         return res;
  1790.     else
  1791.     {
  1792.         if (!directory.bDirList)
  1793.             return PERMISSION_DENIED;
  1794.  
  1795.         if (!bTruematch && !directory.bDirSubdirs)
  1796.             return PERMISSION_DENIED;
  1797.  
  1798.         file = directory.dir;
  1799.  
  1800.         if (enabledFacts[0])
  1801.             fact = _T("type=dir;");
  1802.         else
  1803.             fact = _T("");
  1804.     }
  1805.  
  1806.     CFileStatus64 status;
  1807.     if (GetStatus64(file, status))
  1808.     {
  1809.         if (enabledFacts[1] && !(status.m_attribute & FILE_ATTRIBUTE_DIRECTORY))
  1810.         {
  1811.             CStdString str;
  1812.             str.Format(_T("size=%I64d;"), status.m_size);
  1813.             fact += str;
  1814.         }
  1815.  
  1816.         if (enabledFacts[2])
  1817.         {
  1818.             // Get last modification time
  1819.             FILETIME ftime = status.m_mtime;
  1820.             if (!ftime.dwHighDateTime && !ftime.dwLowDateTime)
  1821.                 ftime = status.m_ctime;
  1822.             if (ftime.dwHighDateTime || ftime.dwLowDateTime)
  1823.             {
  1824.                 SYSTEMTIME time;
  1825.                 FileTimeToSystemTime(&ftime, &time);
  1826.                 CStdString str;
  1827.                 str.Format(_T("modify=%04d%02d%02d%02d%02d%02d;"),
  1828.                     time.wYear,
  1829.                     time.wMonth,
  1830.                     time.wDay,
  1831.                     time.wHour,
  1832.                     time.wMinute,
  1833.                     time.wSecond);
  1834.  
  1835.                 fact += str;
  1836.             }
  1837.         }
  1838.     }
  1839.  
  1840.     fact += _T(" ") + logicalName;
  1841.  
  1842.     return 0;
  1843. }
  1844.  
  1845. void CUser::PrepareAliasMap()
  1846. {
  1847.     /*
  1848.      * Prepare the alias map.
  1849.      * For fast access, aliases are stored as key/value pairs.
  1850.      * The key is the folder part of the alias.
  1851.      * The value is a structure containing the name of the alias
  1852.      * and the target folder.
  1853.      * Example:
  1854.      * Shared folder c:\myfolder, alias d:\myotherfolder\myalias
  1855.      * Key: d:\myotherfolder, Value = myalias, c:\myfolder
  1856.      */
  1857.  
  1858.     aliasMap.clear();
  1859.     virtualAliases.clear();
  1860.     std::vector<t_directory>::const_iterator permIter;
  1861.     std::list<CStdString>::const_iterator aliasIter;
  1862.     for (permIter = permissions.begin(); permIter != permissions.end(); permIter++)
  1863.     {
  1864.         for (aliasIter = permIter->aliases.begin(); aliasIter != permIter->aliases.end(); aliasIter++)
  1865.         {
  1866.             CStdString alias = *aliasIter;
  1867.             DoReplacements(alias);
  1868.  
  1869.             if (alias[0] == '/')
  1870.             {
  1871.                 int pos = alias.ReverseFind('/');
  1872.                 CStdString dir = alias.Left(pos);
  1873.                 if (dir == _T(""))
  1874.                     dir = _T("/");
  1875.                 virtualAliasNames.insert(std::pair<CStdString, CStdString>(dir, alias.Mid(pos + 1)));
  1876.                 virtualAliases[alias + _T("/")] = permIter->dir;
  1877.                 DoReplacements(virtualAliases[alias + _T("/")]);
  1878.                 continue;
  1879.             }
  1880.  
  1881.             int pos = alias.ReverseFind('\\');
  1882.             if (pos == -1)
  1883.                 continue;
  1884.             t_alias aliasStruct;
  1885.             aliasStruct.name = alias.Mid(pos + 1);
  1886.             if (aliasStruct.name == _T(""))
  1887.                 continue;
  1888.             alias = alias.Left(pos);
  1889.  
  1890.             aliasStruct.targetFolder = permIter->dir;
  1891.             DoReplacements(aliasStruct.targetFolder);
  1892.  
  1893.             aliasMap.insert(std::pair<CStdString, t_alias>(alias, aliasStruct));
  1894.         }
  1895.     }
  1896.  
  1897.     if (!pOwner)
  1898.         return;
  1899.  
  1900.     for (permIter = pOwner->permissions.begin(); permIter != pOwner->permissions.end(); permIter++)
  1901.     {
  1902.         for (aliasIter = permIter->aliases.begin(); aliasIter != permIter->aliases.end(); aliasIter++)
  1903.         {
  1904.             CStdString alias = *aliasIter;
  1905.             DoReplacements(alias);
  1906.  
  1907.             if (alias[0] == '/')
  1908.             {
  1909.                 int pos = alias.ReverseFind('/');
  1910.                 CStdString dir = alias.Left(pos);
  1911.                 if (dir == _T(""))
  1912.                     dir = _T("/");
  1913.                 virtualAliasNames.insert(std::pair<CStdString, CStdString>(dir, alias.Mid(pos + 1)));
  1914.                 virtualAliases[alias + _T("/")] = permIter->dir;
  1915.                 DoReplacements(virtualAliases[alias + _T("/")]);
  1916.                 continue;
  1917.             }
  1918.  
  1919.             int pos = alias.ReverseFind('\\');
  1920.             if (pos == -1)
  1921.                 continue;
  1922.             t_alias aliasStruct;
  1923.             aliasStruct.name = alias.Mid(pos + 1);
  1924.             if (aliasStruct.name == _T(""))
  1925.                 continue;
  1926.             alias = alias.Left(pos);
  1927.             
  1928.             aliasStruct.targetFolder = permIter->dir;
  1929.             DoReplacements(aliasStruct.targetFolder);
  1930.         
  1931.             aliasMap.insert(std::pair<CStdString, t_alias>(alias, aliasStruct));
  1932.         }
  1933.     }
  1934. }
  1935.  
  1936. CStdString CUser::GetAliasTarget(const CStdString& path, const CStdString& virtualPath, const CStdString& name) const
  1937. {
  1938.     // Find the target for the alias with the specified path and name
  1939.  
  1940.     for (std::multimap<CStdString, CUser::t_alias>::const_iterator iter = aliasMap.begin(); iter != aliasMap.end(); iter++)
  1941.     {
  1942.         if (iter->first.CompareNoCase(path))
  1943.             continue;
  1944.  
  1945.         if (!iter->second.name.CompareNoCase(name))
  1946.             return iter->second.targetFolder;
  1947.     }
  1948.  
  1949.     for (std::map<CStdString, CStdString>::const_iterator iter2 = virtualAliases.begin(); iter2 != virtualAliases.end(); iter2++)
  1950.     {
  1951.         if (!iter2->first.CompareNoCase(virtualPath))
  1952.             return iter2->second;
  1953.     }
  1954.  
  1955.     return _T("");
  1956. }
  1957.  
  1958. void CPermissions::ReadSettings()
  1959. {
  1960.     TiXmlElement *pXML = COptions::GetXML();
  1961.     if (!pXML)
  1962.         return;
  1963.     
  1964.     TiXmlElement* pGroups = pXML->FirstChildElement("Groups");
  1965.     if (!pGroups)
  1966.         pGroups = pXML->LinkEndChild(new TiXmlElement("Groups"))->ToElement();
  1967.  
  1968.     for (TiXmlElement* pGroup = pGroups->FirstChildElement("Group"); pGroup; pGroup = pGroup->NextSiblingElement("Group"))
  1969.     {
  1970.         t_group group;
  1971.         group.nIpLimit = group.nIpLimit = group.nUserLimit = 0;
  1972.         group.nBypassUserLimit = 2;
  1973.         group.group = ConvFromNetwork(pGroup->Attribute("Name"));
  1974.         if (group.group == _T(""))
  1975.             continue;
  1976.  
  1977.         for (TiXmlElement* pOption = pGroup->FirstChildElement("Option"); pOption; pOption = pOption->NextSiblingElement("Option"))
  1978.         {
  1979.             CStdString name = ConvFromNetwork(pOption->Attribute("Name"));
  1980.             CStdString value = XML::ReadText(pOption);
  1981.  
  1982.             if (name == _T("Bypass server userlimit"))
  1983.                 group.nBypassUserLimit = _ttoi(value);
  1984.             else if (name == _T("User Limit"))
  1985.                 group.nUserLimit = _ttoi(value);
  1986.             else if (name == _T("IP Limit"))
  1987.                 group.nIpLimit = _ttoi(value);
  1988.             else if (name == _T("Enabled"))
  1989.                 group.nEnabled = _ttoi(value);
  1990.             else if (name == _T("Comments"))
  1991.                 group.comment = value;
  1992.             else if (name == _T("ForceSsl"))
  1993.                 group.forceSsl = _ttoi(value);
  1994.         }
  1995.         if (group.nUserLimit < 0 || group.nUserLimit > 999999999)
  1996.             group.nUserLimit = 0;
  1997.         if (group.nIpLimit < 0 || group.nIpLimit > 999999999)
  1998.             group.nIpLimit = 0;
  1999.  
  2000.         ReadIpFilter(pGroup, group);
  2001.  
  2002.         BOOL bGotHome = FALSE;
  2003.         ReadPermissions(pGroup, group, bGotHome);
  2004.         //Set a home dir if no home dir could be read
  2005.         if (!bGotHome && !group.permissions.empty())
  2006.             group.permissions.begin()->bIsHome = TRUE;
  2007.  
  2008.         ReadSpeedLimits(pGroup, group);
  2009.  
  2010.         if (m_GroupsList.size() < 200000)
  2011.             m_GroupsList.push_back(group);
  2012.     }
  2013.         
  2014.     TiXmlElement* pUsers = pXML->FirstChildElement("Users");
  2015.     if (!pUsers)
  2016.         pUsers = pXML->LinkEndChild(new TiXmlElement("Users"))->ToElement();
  2017.  
  2018.     for (TiXmlElement* pUser = pUsers->FirstChildElement("User"); pUser; pUser = pUser->NextSiblingElement("User"))
  2019.     {
  2020.         CUser user;
  2021.         user.nIpLimit = user.nIpLimit = user.nUserLimit = 0;
  2022.         user.nBypassUserLimit = 2;
  2023.         user.user = ConvFromNetwork(pUser->Attribute("Name"));
  2024.         if (user.user == _T(""))
  2025.             continue;
  2026.  
  2027.         for (TiXmlElement* pOption = pUser->FirstChildElement("Option"); pOption; pOption = pOption->NextSiblingElement("Option"))
  2028.         {
  2029.             CStdString name = ConvFromNetwork(pOption->Attribute("Name"));
  2030.             CStdString value = XML::ReadText(pOption);
  2031.  
  2032.             if (name == _T("Pass"))
  2033.             {
  2034.                 // If provided password is not a MD5 has, convert it into a MD5 hash
  2035.                 if (value != _T("") && value.GetLength() != 32)
  2036.                 {
  2037.                     char *tmp = ConvToNetwork(value);
  2038.                     if (!tmp)
  2039.                     {
  2040.                         tmp = new char[1];
  2041.                         tmp[0] = 0;
  2042.                     }
  2043.                     MD5 md5;
  2044.                     md5.update((unsigned char *)tmp, strlen(tmp));
  2045.                     md5.finalize();
  2046.                     char *res = md5.hex_digest();
  2047.  
  2048.                     pOption->Clear();
  2049.                     XML::SetText(pOption, res);
  2050.                     user.password = res;
  2051.                     delete [] tmp;
  2052.                     delete [] res;
  2053.                 }
  2054.                 else
  2055.                     user.password = value;
  2056.             }
  2057.             else if (name == _T("Bypass server userlimit"))
  2058.                 user.nBypassUserLimit = _ttoi(value);
  2059.             else if (name == _T("User Limit"))
  2060.                 user.nUserLimit = _ttoi(value);
  2061.             else if (name == _T("IP Limit"))
  2062.                 user.nIpLimit = _ttoi(value);
  2063.             else if (name == _T("Group"))
  2064.                 user.group = value;
  2065.             else if (name == _T("Enabled"))
  2066.                 user.nEnabled = _ttoi(value);
  2067.             else if (name == _T("Comments"))
  2068.                 user.comment = value;
  2069.             else if (name == _T("ForceSsl"))
  2070.                 user.forceSsl = _ttoi(value);
  2071.         }
  2072.         if (user.nUserLimit < 0 || user.nUserLimit > 999999999)
  2073.             user.nUserLimit = 0;
  2074.         if (user.nIpLimit < 0 || user.nIpLimit > 999999999)
  2075.             user.nIpLimit = 0;
  2076.  
  2077.         if (user.group != _T(""))
  2078.         {
  2079.             for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  2080.                 if (groupiter->group == user.group)
  2081.                 {
  2082.                     user.pOwner = &(*groupiter);
  2083.                     break;
  2084.                 }
  2085.         
  2086.             if (!user.pOwner)
  2087.                 user.group = _T("");
  2088.         }
  2089.             
  2090.         ReadIpFilter(pUser, user);
  2091.  
  2092.         BOOL bGotHome = FALSE;
  2093.         ReadPermissions(pUser, user, bGotHome);
  2094.         user.PrepareAliasMap();
  2095.                 
  2096.         //Set a home dir if no home dir could be read
  2097.         if (!bGotHome && !user.pOwner)
  2098.         {
  2099.             if (!user.permissions.empty())
  2100.                 user.permissions.begin()->bIsHome = TRUE;
  2101.         }
  2102.             
  2103.         std::vector<t_directory>::iterator iter;
  2104.         for (iter = user.permissions.begin(); iter != user.permissions.end(); iter++)
  2105.         {
  2106.             if (iter->bIsHome)
  2107.             {
  2108.                 user.homedir = iter->dir;
  2109.                 break;
  2110.             }
  2111.         }
  2112.         if (user.homedir == _T("") && user.pOwner)
  2113.         {
  2114.             for (iter = user.pOwner->permissions.begin(); iter != user.pOwner->permissions.end(); iter++)
  2115.             {
  2116.                 if (iter->bIsHome)
  2117.                 {
  2118.                     user.homedir = iter->dir;
  2119.                     break;
  2120.                 }
  2121.             }
  2122.         }
  2123.             
  2124.         ReadSpeedLimits(pUser, user);
  2125.  
  2126.         if (m_UsersList.size() < 200000)
  2127.             m_UsersList.push_back(user);
  2128.     }
  2129.     COptions::FreeXML(pXML, false);
  2130.  
  2131.     EnterCritSection(m_sync);
  2132.  
  2133.     m_sGroupsList.clear();
  2134.     for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  2135.         m_sGroupsList.push_back(*groupiter);
  2136.  
  2137.     m_sUsersList.clear();
  2138.     for (t_UsersList::iterator iter = m_UsersList.begin(); iter != m_UsersList.end(); iter++)
  2139.     {
  2140.         CUser user = *iter;
  2141.         user.pOwner = NULL;
  2142.         if (user.group != _T(""))
  2143.         {
  2144.             for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  2145.                 if (groupiter->group == user.group)
  2146.                 {
  2147.                     user.pOwner = &(*groupiter);
  2148.                     break;
  2149.                 }
  2150.         }
  2151.         m_sUsersList.push_back(user);
  2152.     }
  2153.  
  2154.     LeaveCritSection(m_sync);
  2155. }
  2156.  
  2157. // Replace :u and :g (if a group it exists)
  2158. void CUser::DoReplacements(CStdString& path) const
  2159. {
  2160.     path.Replace(_T(":u"), user);
  2161.     path.Replace(_T(":U"), user);
  2162.     if (group != _T(""))
  2163.     {
  2164.         path.Replace(_T(":g"), group);
  2165.         path.Replace(_T(":G"), group);
  2166.     }
  2167. }
  2168.  
  2169. bool CPermissions::WildcardMatch(CStdString string, CStdString pattern) const
  2170. {
  2171.     if (pattern == _T("*") || pattern == _T("*.*"))
  2172.         return true;
  2173.  
  2174.     // Do a really primitive wildcard check, does even ignore ?
  2175.     string.MakeLower();
  2176.     pattern.MakeLower();
  2177.  
  2178.     bool starFirst = false;
  2179.     while (pattern != _T(""))
  2180.     {
  2181.         int pos = pattern.Find('*');
  2182.         if (pos == -1)
  2183.         {
  2184.             if (starFirst)
  2185.             {
  2186.                 if (string.GetLength() > pattern.GetLength())
  2187.                     string = string.Right(pattern.GetLength());
  2188.             }
  2189.             if (pattern != string)
  2190.                 return false;
  2191.             else
  2192.                 return true;
  2193.         }
  2194.         else if (!pos)
  2195.         {
  2196.             starFirst = true;
  2197.             pattern = pattern.Mid(1);
  2198.         }
  2199.         else
  2200.         {
  2201.             int npos = string.Find(pattern.Left(pos));
  2202.             if (npos == -1)
  2203.                 return false;
  2204.             if (npos && !starFirst)
  2205.                 return false;
  2206.             pattern = pattern.Mid(pos + 1);
  2207.             string = string.Mid(npos + pos);
  2208.  
  2209.             starFirst = true;
  2210.         }
  2211.     }
  2212.     return true;
  2213. }
  2214.  
  2215. char* CPermissions::ConvertFilename(const CStdString& filename, bool useUTF8)
  2216. {
  2217.     if (useUTF8)
  2218.         return ConvToNetwork(filename);
  2219.     
  2220.     const CStdStringA& tmp = ConvToLocal(filename);
  2221.     
  2222.     char* str = new char[strlen(tmp) + 1];
  2223.     strcpy(str, tmp);
  2224.     return str;
  2225. }
  2226.  
  2227. void CPermissions::DestroyDirlisting(struct t_dirlisting* pListing)
  2228. {
  2229.     while (pListing)
  2230.     {
  2231.         t_dirlisting *pPrev = pListing;
  2232.         pListing = pListing->pNext;
  2233.         delete pPrev;
  2234.     }
  2235. }
  2236.